<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html
    PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<!-- walkthrough.qdoc -->
<head>
  <title>MFC to Qt Migration - Walkthrough</title>
  <link href="classic.css" rel="stylesheet" type="text/css" />
</head>
<body>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tr>
<td align="left" valign="top" width="32"><img src="images/qt-logo.png" align="left" width="57" height="67" border="0" /></td>
<td width="1">&nbsp;&nbsp;</td><td class="postheader" valign="center"><a href="index.html"><font color="#004faf">Home</font></a></td>
</tr></table><h1 class="title">MFC to Qt Migration - Walkthrough<br /><span class="subtitle"></span>
</h1>
<ul><li><a href="#introduction">Introduction</a></li>
<ul><li><a href="#goals-for-this-walkthrough">Goals for this Walkthrough</a></li>
<li><a href="#a-note-about-mfc-s-memory-leak-detection">A note about MFC's memory leak detection</a></li>
</ul>
<li><a href="#getting-started">Getting Started</a></li>
<ul><li><a href="#plugin-extension">Plugin extension</a></li>
<li><a href="#linking-against-qt">Linking against Qt</a></li>
<li><a href="#replacing-the-mfc-event-loop">Replacing the MFC event loop</a></li>
<li><a href="#replacing-a-dialog">Replacing a Dialog</a></li>
</ul>
<li><a href="#new-functionality-with-qt">New Functionality with Qt</a></li>
<ul><li><a href="#creating-qt-widgets">Creating Qt widgets</a></li>
<li><a href="#a-new-qt-dialog">A new Qt Dialog</a></li>
</ul>
<li><a href="#removing-mfc">Removing MFC</a></li>
<ul><li><a href="#using-the-qt-build-system">Using the Qt build system</a></li>
<li><a href="#replacing-the-childview">Replacing the ChildView</a></li>
<li><a href="#replacing-the-mainframe">Replacing the MainFrame</a></li>
<li><a href="#replacing-the-mfc-application">Replacing the MFC application</a></li>
<li><a href="#cleaning-up">Cleaning up</a></li>
</ul>
</ul>
<a name="introduction"></a>
<h2>Introduction</h2>
<p>This walkthrough covers the migration of an MFC based program, generated by Microsoft Visual Studio's MFC Application Wizard, to the Qt toolkit using the <i>Windows Migration Framework</i>.</p>
<a name="goals-for-this-walkthrough"></a>
<h3>Goals for this Walkthrough</h3>
<p>The original application, located in the <tt>step1</tt> directory, is a trivial SDI program with a main window including a menu bar, a single child view and an about dialog. The walkthrough will demonstrate how easy it is to gradually replace the MFC code in an existing application with multiplatform Qt code, while being able to extend the program with new functionality based on Qt. The final step will be a complete replacement of the Windows-only MFC code with a single source that can be compiled for any platform supported by Qt, including Windows, Mac OS X, Linux/Unix and embedded Linux.</p>
<a name="a-note-about-mfc-s-memory-leak-detection"></a>
<h3>A note about MFC's memory leak detection</h3>
<p>MFC contains a checkpoint-based memory leak detection mechanism. This mechanism does not handle well Qt's system of allocating global static objects. The result is that when running applications that combine Qt and MFC (like the examples below) from within Visual Studio, one will get a report about leaked objects upon application exit. These warnings can safely be ignored.</p>
<a name="getting-started"></a>
<h2>Getting Started</h2>
<p>Load the project file <tt>qtmfc1.dsp</tt> into a Workspace in Visual Studio and make sure that everything is set up correctly by building and running the project.</p>
<p>The MFC application has an interface to use dialogs provided by an external DLL that will be explicitly loaded. The interface is fairly simple: the DLL must export a C function called <tt>showDialog</tt> that can take a window handle <i>parent</i>. The DLL must show its dialog modally, and when the function returns the DLL is unloaded again.</p>
<p>The code that does this in the MFC application is in the OnAppAbout command handler.</p>
<pre> void WindowsApp::OnAppAbout()
 {
     HMODULE mod = LoadLibrary( &quot;qtdialog.dll&quot; );
     if ( mod ) {
         typedef BOOL(*pShowDialog)(HWND parent);
         pShowDialog showDialog = (pShowDialog)GetProcAddress( mod, &quot;showDialog&quot; );
         if ( showDialog )
             showDialog( theApp.m_pMainWnd-&gt;m_hWnd );

         FreeLibrary( mod );
     } else {
         CAboutDlg aboutDlg;
         aboutDlg.DoModal();
     }
 }</pre>
<p>If the DLL can be loaded and exports the <tt>showDialog</tt> symbol the exported function is called, otherwise a default MFC about dialog is displayed.</p>
<a name="plugin-extension"></a>
<h3>Plugin extension</h3>
<p>The project in the <tt>qtdll</tt> example directory implements the plugin interface using the <a href="http://qt.nokia.com/doc/4.6/qmessagebox.html">QMessageBox</a> class. To use this class a <a href="http://qt.nokia.com/doc/4.6/qapplication.html">QApplication</a> object must exist in the current process, and the Qt events must be processed in addition to the standard event dispatching performed by the running MFC application.</p>
<p>The DLL also has to make sure that it can be loaded together with other Qt based DLLs in the same process (in which case a <a href="http://qt.nokia.com/doc/4.6/qapplication.html">QApplication</a> object will probably exist already), and that the DLL that creates the <a href="http://qt.nokia.com/doc/4.6/qapplication.html">QApplication</a> object remains loaded in memory to avoid other DLLs using memory that is no longer available to the process.</p>
<p>All these issues are handled by the <a href="qmfcapp.html#pluginInstance">QMfcApp::pluginInstance</a>() function. This function creates a <a href="http://qt.nokia.com/doc/4.6/qapplication.html">QApplication</a> object and installs a message hook that merges the Qt event loop with the existing standard Win32 message pump of MFC. If an instance to the DLL is passed as a parameter the function will also increase the DLL's reference count so that it is not unloaded before the process exits.</p>
<p>This function can be used in an implementation of the <tt>DllMain</tt> entry point function when the DLL is loaded. A static bool variable is used to remember whether this DLL is responsible for the <a href="http://qt.nokia.com/doc/4.6/qapplication.html">QApplication</a> object, and when the DLL is unloaded the <a href="http://qt.nokia.com/doc/4.6/qapplication.html">QApplication</a> object, accessible through the global <tt>qApp</tt> pointer, can be deleted.</p>
<p>To use the function and the other Qt classes involved we also need to include a few header files.</p>
<pre> #include &lt;qmfcapp.h&gt;
 #include &lt;qwinwidget.h&gt;

 #include &lt;QtGui/QMessageBox&gt;
 #include &lt;windows.h&gt;

 BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID <span class="comment">/*lpvReserved*/</span> )
 {
     static bool ownApplication = FALSE;

     if ( dwReason == DLL_PROCESS_ATTACH )
         ownApplication = QMfcApp::pluginInstance( hInstance );
     if ( dwReason == DLL_PROCESS_DETACH &amp;&amp; ownApplication )
         delete qApp;

     return TRUE;
 }</pre>
<p>The DLL interface is then implemented using an exported C function called <tt>showDialog</tt>. The <a href="qwinwidget.html">QWinWidget</a> class is used to provide the proper placement and stacking of the Qt dialog.</p>
<pre> extern &quot;C&quot; __declspec(dllexport) bool showDialog( HWND parent )
 {
     QWinWidget win( parent );
     win.showCentered();
     QMessageBox::about( &amp;win, &quot;About QtMfc&quot;, &quot;QtMfc Version 1.0\nCopyright (C) 2003&quot; );

     return TRUE;
 }</pre>
<a name="linking-against-qt"></a>
<h3>Linking against Qt</h3>
<p>To use Qt classes directly in the MFC application we must link the application against the Qt libraries, and add the location of the Qt header files to the compiler's include directories.</p>
<p>The <tt>step2</tt> directory includes a <tt>.pro</tt> file that generates a proper <tt>.dsp</tt> file that has all the required settings. Run c{qmake -tp vc} in the directory to generate that <tt>.dsp</tt> file, and check the settings necessary in case you want to modify the Visual Studio project manually.</p>
<a name="replacing-the-mfc-event-loop"></a>
<h3>Replacing the MFC event loop</h3>
<p>To be able to use Qt, we need to create a <a href="http://qt.nokia.com/doc/4.6/qapplication.html">QApplication</a> object. The <a href="http://qt.nokia.com/doc/4.6/qapplication.html">QApplication</a> class controls the event delivery and display management for all Qt objects and widgets.</p>
<p>In the original MFC project the wizard generated <tt>WindowsApp</tt> class, a subclass of <tt>CWinApp</tt>, runs the event loop in the default implementation of <tt>Run()</tt>. The MFC event loop is a standard Win32 event loop, but uses the CWinApp API <tt>PreTranslateMessage()</tt> to activate accelerators.</p>
<p>In order to keep MFC accelerators working we must use the <tt>QApplication</tt> subclass <tt>QMfcApp</tt> that is provided by the Windows Migration framework and which merges the Qt and the MFC event loops.</p>
<p>The first step of the Qt migration is to reimplement the <tt>Run()</tt> function in the <tt>WindowsApp</tt> class. We can either use the wizard to add a reimplementation of Run(), or add the reimplementation ourselves to the class declaration in the <tt>qtmfc.h</tt> header file:</p>
<pre> class WindowsApp : public CWinApp
 {
 public:
         WindowsApp();

<span class="comment"> // Overrides</span>
         <span class="comment">// ClassWizard generated virtual function overrides</span>
         <span class="comment">//{{AFX_VIRTUAL(WindowsApp)</span>
         public:
         virtual BOOL InitInstance();
         virtual BOOL Run();
         <span class="comment">//}}AFX_VIRTUAL</span>

<span class="comment"> // Implementation</span>

 public:
         <span class="comment">//{{AFX_MSG(WindowsApp)</span>
         afx_msg void OnAppAbout();
         <span class="comment">//}}AFX_MSG</span>
         DECLARE_MESSAGE_MAP()
 };</pre>
<p>The implementation of this function is in the <tt>qtmfc.cpp</tt> source file. To use the <a href="qmfcapp.html">QMfcApp</a> API we need to <tt>#include</tt> the <tt>qmfcapp.h</tt> header file.</p>
<pre> #include &quot;stdafx.h&quot;
 #include &quot;qtmfc.h&quot;

 #include &quot;mainframe.h&quot;

 #include &lt;qmfcapp.h&gt;

 BOOL WindowsApp::Run()
 {
     return QMfcApp::run( this );
 }</pre>
<p>The implementation uses the static run() function of the <a href="qmfcapp.html">QMfcApp</a> class to implicitly instantiate a <a href="http://qt.nokia.com/doc/4.6/qapplication.html">QApplication</a> object, and run the event loops for both Qt and MFC:</p>
<p>The code in the plugin DLL does not need to be modified: Since we have a <a href="http://qt.nokia.com/doc/4.6/qapplication.html">QApplication</a> object created in the application itself the pluginInstance() function will do nothing, and the DLL will open the message box in the exported function just like before.</p>
<a name="replacing-a-dialog"></a>
<h3>Replacing a Dialog</h3>
<p>Instead of using the Qt plugin DLL we will now replace the MFC About Dialog directly in the application source code. Using the Visual Studio integration toolbar we could quickly create a new <a href="http://qt.nokia.com/doc/4.6/qdialog.html">QDialog</a> with <i>Qt Designer</i> from scratch. Or convert the existing dialogs from Microsoft resource files into <i>Qt Designer</i> <tt>.ui</tt> files by using a conversion tool such as <a href="http://www.kdab.net/?page=products&sub=knut">KDAB's KNUT</a> tool. But for a basic dialog as the one in this example, it is even easier to use the <a href="http://qt.nokia.com/doc/4.6/qmessagebox.html#about">QMessageBox::about</a>() function as we did in the plugin code shown earlier.</p>
<pre> #include &quot;stdafx.h&quot;
 #include &quot;qtmfc.h&quot;

 #include &quot;mainframe.h&quot;

 #include &lt;qmfcapp.h&gt;
 #include &lt;qwinwidget.h&gt;
 #include &lt;QtGui/QMessageBox&gt;</pre>
<p>To use the <a href="http://qt.nokia.com/doc/4.6/qmessagebox.html">QMessageBox</a> API we must include the appropriate header. Since we need to create the <a href="http://qt.nokia.com/doc/4.6/qmessagebox.html">QMessageBox</a> as a child of the MFC based main window we also need to use the <tt>QWinWidget</tt> class again and include that header as well.</p>
<pre><span class="comment"> // WindowsApp message handlers</span>

<span class="comment"> // App command to run the dialog</span>
 void WindowsApp::OnAppAbout()
 {
     QWinWidget win( theApp.m_pMainWnd );
     win.showCentered();
     QMessageBox::about( &amp;win, &quot;About QtMfc&quot;, &quot;QtMfc Version 1.0\nCopyright (C) 2003&quot; );
 }</pre>
<p>We can remove the class declaration and implementation of the CAboutDlg class from the source file, and use the <a href="qwinwidget.html">QWinWidget</a> and <a href="http://qt.nokia.com/doc/4.6/qmessagebox.html">QMessageBox</a> API in the implementation of the <tt>WindowsApp::OnAppAbout()</tt> command handler.</p>
<p>A <a href="qwinwidget.html">QWinWidget</a> object is created on the stack, using the MFC application's main window as the parent window. The showCentered() API is used to make sure that the Qt message box, which uses the <a href="qwinwidget.html">QWinWidget</a> object as its parent, will open centered over the main window.</p>
<a name="new-functionality-with-qt"></a>
<h2>New Functionality with Qt</h2>
<p>We can now add new functionality to the MFC application using Qt. We will add a Qt based user interface to the MFC child view, and add an additional modeless options dialog created with <i>Qt Designer</i>.</p>
<a name="creating-qt-widgets"></a>
<h3>Creating Qt widgets</h3>
<p>To be able to create Qt widgets in the initialization of the MFC application we must first create an instance of <a href="http://qt.nokia.com/doc/4.6/qapplication.html">QApplication</a>. The current use of the static <tt>QMfcApp::run()</tt> API creates the <a href="http://qt.nokia.com/doc/4.6/qapplication.html">QApplication</a> object in the <tt>Run()</tt> reimplementation of the CWinApp subclass, while the GUI is already being created in the <tt>InitInstance</tt> reimplementation.</p>
<pre> BOOL WindowsApp::InitInstance()
 {
         <span class="comment">// Standard initialization</span>

 #if _MFC_VER &lt; 0x0700
 #ifdef _AFXDLL
         Enable3dControls();                     <span class="comment">// Call this when using MFC in a shared DLL</span>
 #else
         Enable3dControlsStatic();       <span class="comment">// Call this when linking to MFC statically</span>
 #endif
 #endif

         <span class="comment">// Change the registry key under which our settings are stored.</span>
         SetRegistryKey(_T(&quot;Local AppWizard-Generated Applications&quot;));

         <span class="comment">// Qt initialization</span>
         QMfcApp::instance(this);

         MainFrame* pFrame = new MainFrame;
         return true;
 }</pre>
<p>To create the <a href="http://qt.nokia.com/doc/4.6/qapplication.html">QApplication</a> object in the <tt>InitInstance</tt> implementation we must use the static function <tt>QMfcApp::instance()</tt>.</p>
<pre> BOOL WindowsApp::Run()
 {
     int result = QMfcApp::run(this);
     delete qApp;
     return result;
 }</pre>
<p><tt>QMfcApp:run()</tt> will then use that instance, which must then be deleted explicitly using the global <tt>qApp</tt> pointer.</p>
<p>MFC's window creation infrastructure is rather complicated, and we must add a message handler for the <tt>WM_CREATE</tt> and <tt>WM_DESTROY</tt> messages to be able to add children only when the creation of the MFC window is complete, and to delete the children before the MFC window is destroyed.</p>
<pre><span class="comment"> // ChildView window</span>

 class QWinWidget;

 class ChildView : public CWnd
 {
<span class="comment"> // Construction</span>
 public:
         ChildView();</pre>
<pre> ...</pre>
<pre>         <span class="comment">// Generated message map functions</span>
 protected:
         <span class="comment">//{{AFX_MSG(ChildView)</span>
         afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
         afx_msg void OnDestroy();
         afx_msg void OnPaint();
         <span class="comment">//}}AFX_MSG</span>
         DECLARE_MESSAGE_MAP()

 private:
         QWinWidget *widget;
 };</pre>
<p>We can again use Visual Studio's wizards, or simply add the code ourselves. We also add a forward declaration of the <a href="qwinwidget.html">QWinWidget</a> class, and add a pointer to that class as a member of the ChildView.</p>
<pre> #include &quot;stdafx.h&quot;
 #include &quot;qtmfc.h&quot;
 #include &quot;childview.h&quot;

 #include &lt;qwinwidget.h&gt;
 #include &lt;QtGui/QLabel&gt;
 #include &lt;QtGui/QLineEdit&gt;
 #include &lt;QtGui/QLayout&gt;</pre>
<p>We include the headers for the Qt widget we want to use, as well as the header for the <a href="qwinwidget.html">QWinWidget</a> class.</p>
<pre> ChildView::ChildView()
 : widget( 0 )
 {
 }</pre>
<p>We initialize the pointer to the <a href="qwinwidget.html">QWinWidget</a> member to zero. We cannot create it yet, since the MFC window has not yet been created. This happens only when the <tt>MainWindow::OnCreate()</tt> message handler calls the <tt>Create</tt> function, which then calls our <tt>ChildView::OnCreate</tt> implementation.</p>
<pre> BEGIN_MESSAGE_MAP(ChildView,CWnd )
         <span class="comment">//{{AFX_MSG_MAP(ChildView)</span>
         ON_WM_CREATE()
         ON_WM_DESTROY()
         ON_WM_PAINT()
         <span class="comment">//}}AFX_MSG_MAP</span>
 END_MESSAGE_MAP()</pre>
<p>The message handlers are added to the message map.</p>
<pre> int ChildView::OnCreate(LPCREATESTRUCT lpCreateStruct)
 {
     if (CWnd::OnCreate( lpCreateStruct ) == -1 )
         return -1;</pre>
<p>The implementation of the <tt>OnCreate</tt> message handler calls and verifies the parent class function and returns an error code if an error occurred.</p>
<pre>     widget = new QWinWidget( this );
     QHBoxLayout *hbox = new QHBoxLayout( widget );

     QLabel *label = new QLabel( &quot;Enter text:&quot;, widget );
     QLineEdit *edit = new QLineEdit( widget );
     hbox-&gt;addWidget( label );
     hbox-&gt;addWidget( edit );

     widget-&gt;move( 0, 0 );
     widget-&gt;show();

     return 0;
 }</pre>
<p>Now we can create the <a href="qwinwidget.html">QWinWidget</a> instance with <tt>this</tt> CWnd instance as a parent window, and use that instance as a parent to the QWidgets we want to use to create the user interface. Since <a href="qwinwidget.html">QWinWidget</a> is a proper <a href="http://qt.nokia.com/doc/4.6/qwidget.html">QWidget</a> it can be laid out, and we move the Qt GUI to the upper left corner of the MFC child and show() the user interface immediately.</p>
<pre> BOOL ChildView::PreCreateWindow(CREATESTRUCT&amp; cs)
 {
         if (!CWnd::PreCreateWindow(cs))
                 return FALSE;

         cs.dwExStyle |= WS_EX_CLIENTEDGE;
         cs.style &amp;= ~WS_BORDER;
         cs.style |= WS_CLIPCHILDREN;
         cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS,
                 ::LoadCursor(NULL, IDC_ARROW), HBRUSH(COLOR_WINDOW+1), NULL);

         return TRUE;
 }</pre>
<p>Since the <tt>ChildView</tt> class of MFC was not supposed to be a container for other windows we now see some bad flickering whenever we resize the main window. The <tt>QLabel</tt> widget is obviously painted over by the <tt>ChildView</tt> window on every resize before it has a chance to fill its own background. To prevent this we must change the style of the window to include the <tt>CS_CLIPCHILDREN</tt> flag.</p>
<pre> void ChildView::OnDestroy()
 {
     delete widget;
     widget = 0;

     CWnd::OnDestroy();
 }</pre>
<p>In the <tt>OnDestroy</tt> message handler we delete the <a href="qwinwidget.html">QWinWidget</a> instance, which deletes all other QWidgets we have created as children.</p>
<a name="a-new-qt-dialog"></a>
<h3>A new Qt Dialog</h3>
<p>To add a new dialog we use the Visual Studio integration toolbar's &quot;New Qt Dialog&quot; button. We add a <i>Qt Designer</i> <tt>.ui</tt> file &quot;optionsdialog.ui&quot; to the current project, and add the required build steps to generate a C++ class from that file. </p>
<!-- <p>If you don't have the integration toolbar, add the following commands to the custom build step of the <tt>.ui</tt> file:</p>
<pre> %qtdir%\bin\uic.exe $(InputPath) -o $(InputDir)\$(InputName).h
 %qtdir%\bin\uic.exe $(InputPath) -i $(InputName).h -o $(InputDir)\$(InputName).cpp
 %qtdir%\bin\moc.exe $(InputDir)\$(InputName).h -o $(InputDir)\moc_$(InputName).cpp</pre>
<p>And the following Output files:</p>
<pre> $(InputDir)\$(InputName).h
 $(InputDir)\$(InputName).cpp
 $(InputDir)\moc_$(InputName).cpp</pre>
--> MFC projects have the precompiled header option turned on by default, and since Qt or <i>Qt Designer</i> cannot rely on the compiler used supporting precompiled headers the respective preprocessor directives are missing from the generated <tt>.cpp</tt> files. We must turn the precompiled headers option off for those files, but we can just as well turn them off for the complete project.<p>To be able to invoke the dialog we add a new entry to the MFC menu using the Visual Studio resource editor. The menu entry is called &quot;Options&quot;, and has the ID <tt>ID_EDIT_OPTIONS</tt>.</p>
<pre> class WindowsApp : public CWinApp
 {
 public:</pre>
<pre>  ...</pre>
<pre><span class="comment"> // Implementation</span>

 public:
         <span class="comment">//{{AFX_MSG(WindowsApp)</span>
         afx_msg void OnAppAbout();
         afx_msg void OnAppOptions();
         <span class="comment">//}}AFX_MSG</span>
         DECLARE_MESSAGE_MAP()
 };</pre>
<p>We add a command handler for that option to the WindowsApp class and add the mapping to the message map. We also include the generated header file.</p>
<pre> #include &lt;qmfcapp.h&gt;
 #include &lt;qwinwidget.h&gt;
 #include &lt;QtGui/QMessageBox&gt;
 #include &quot;ui_optionsdialog.h&quot;

 BEGIN_MESSAGE_MAP(WindowsApp, CWinApp)
         <span class="comment">//{{AFX_MSG_MAP(WindowsApp)</span>
         ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
         ON_COMMAND(ID_EDIT_OPTIONS, OnAppOptions)
         <span class="comment">//}}AFX_MSG_MAP</span>
 END_MESSAGE_MAP()</pre>
<p>The implementation of the command handler once again uses the <a href="qwinwidget.html">QWinWidget</a> class to make sure that the dialog is properly positioned and stacked. Since we want the dialog to be modeless we cannot create the <a href="qwinwidget.html">QWinWidget</a> on the stack, since it would be deleted when it leaves the scope, and all its children, including the dialog, would be deleted as well.</p>
<pre> void WindowsApp::OnAppOptions()
 {
     QWinWidget *win = new QWinWidget(theApp.m_pMainWnd);
     win-&gt;showCentered();

     QDialog *dialog = new QDialog(win);
     Ui::OptionsDialog ui;
     ui.setupUi(dialog);
     dialog-&gt;setAttribute(Qt::WA_DeleteOnClose);
     dialog-&gt;show();
 }</pre>
<p>Instead we create <a href="qwinwidget.html">QWinWidget</a> on the heap, using operator <tt>new</tt>, and use the <tt>WDestructiveClose</tt> widget flag when creating the dialog as a child, also with operator <tt>new</tt>.</p>
<p>Both the <a href="qwinwidget.html">QWinWidget</a> object and the modeless dialog will be destroyed when the dialog is closed, e.g&#x2e; when clicking the OK button.</p>
<a name="removing-mfc"></a>
<h2>Removing MFC</h2>
<p>We will now turn the complete MFC/Qt hybrid application into a genuine, multiplatform Qt application. To make our application compilable with different compilers for different platforms we need to remove the dependency on Visual C++ and Visual Studio, and replace the Visual Studio project file with a qmake project.</p>
<a name="using-the-qt-build-system"></a>
<h3>Using the Qt build system</h3>
<p>The project file lists all the sources involved.</p>
<pre> TEMPLATE = app
 TARGET   = QtMfc4

 DEFINES -= UNICODE
 DEFINES += _AFXDLL WINVER=0x0500
 QMAKE_LIBS_QT_ENTRY =

 HEADERS = childview.h mainframe.h qtmfc.h stdafx.h
 SOURCES = childview.cpp mainframe.cpp qtmfc.cpp stdafx.cpp
 FORMS   = optionsdialog.ui
 RC_FILE = qtmfc.rc

 include(../../../src/qtwinmigrate.pri)</pre>
<p>Until we have completed the transition we must still link against the Windows Migration Framework, compile the Visual C++ resources, set the preprocessor define to pull in the MFC DLL, and turn off UNICODE to avoid library conflicts with the non-UNICODE MFC version. We must also remove the <tt>qtmain</tt> library which implements the <tt>WinMain</tt> entry point function to call the multiplatform <tt>main</tt> entry point.</p>
<p>Running <tt>qmake -tp vc</tt> on the <tt>.pro</tt> file will generate a new <tt>.dsp</tt> file that we can use in Visual Studio to compile and link the application.</p>
<a name="replacing-the-childview"></a>
<h3>Replacing the ChildView</h3>
<p>The first MFC class we will move over to Qt is the ChildView class. We replace the old class declaration with the declaration of a <a href="http://qt.nokia.com/doc/4.6/qwidget.html">QWidget</a> subclass.</p>
<pre> #ifndef CHILDVIEW_H
 #define CHILDVIEW_H

 #include &lt;QtGui/QWidget&gt;

 class ChildView : public QWidget
 {
 public:
     ChildView(QWidget *parent = 0);

 protected:
     void paintEvent(QPaintEvent *);
 };

 #endif</pre>
<p>We don't need any creation and destruction message handlers anymore, and the <a href="qwinwidget.html">QWinWidget</a> member is obsolete as well. However, we will keep an event handler for paint events as in the original class.</p>
<pre> ChildView::ChildView(QWidget *parent)
 : QWidget(parent)
 {
     QWidget *widget = new QWidget(this);
     QHBoxLayout *hbox = new QHBoxLayout(widget);

     QLabel *label = new QLabel(&quot;Enter text:&quot;, widget);
     QLineEdit *edit = new QLineEdit(widget);

     hbox-&gt;addWidget(label);
     hbox-&gt;addWidget(edit);

     widget-&gt;move(0, 0);
     setBackgroundRole(QPalette::Base);
 }

 void ChildView::paintEvent(QPaintEvent * <span class="comment">/*e*/</span>)
 {
     QPainter painter(this);
 }</pre>
<p>The implementation of the class creates the user interface elements directly in the constructor and sets the erase color property to white. The paintEvent does nothing, at least for now.</p>
<a name="replacing-the-mainframe"></a>
<h3>Replacing the MainFrame</h3>
<p>The next MFC class we will move over to Qt is the MainFrame class. We could use <i>Qt Designer</i> to generate a main window in a visual environment, but it's just as easy to add the few elements manually.</p>
<pre> #ifndef MAINFRAME_H
 #define MAINFRAME_H

 #include &lt;QtGui/QMainWindow&gt;

 class ChildView;

 class MainFrame : public QMainWindow
 {
     Q_OBJECT
 public:
     MainFrame(QWidget *parent = 0);

 protected Q_SLOTS:
     void editOptions();
     void helpAbout();

 private:
     ChildView *view;
 };

 #endif</pre>
<p>The class implements the constructor, and keeps a reference to the ChildView object. The <tt>Q_OBJECT</tt> macro is used to allow this class to declare signals and slots. We add two slots, <tt>editOptions</tt> and <tt>helpAbout</tt>.</p>
<pre> MainFrame::MainFrame(QWidget *parent)
 : QMainWindow(parent)
 {
     QMenu *filePopup = menuBar()-&gt;addMenu(&quot;&amp;File&quot;);
     filePopup-&gt;addAction(&quot;&amp;Exit&quot;, this, SLOT(close()));

     QMenu *editPopup = menuBar()-&gt;addMenu(&quot;&amp;Edit&quot;);
     editPopup-&gt;addAction(&quot;&amp;Undo&quot;, 0, 0, Qt::CTRL + Qt::Key_Z);
     editPopup-&gt;addSeparator();
     editPopup-&gt;addAction(&quot;Cu&amp;t&quot;, 0, 0, Qt::CTRL + Qt::Key_X);
     editPopup-&gt;addAction(&quot;&amp;Copy&quot;, 0, 0, Qt::CTRL + Qt::Key_C);
     editPopup-&gt;addAction(&quot;&amp;Paste&quot;, 0, 0, Qt::CTRL + Qt::Key_V);
     editPopup-&gt;addSeparator();
     editPopup-&gt;addAction(&quot;&amp;Options...&quot;, this, SLOT(editOptions()));

     QMenu *helpPopup = menuBar()-&gt;addMenu(&quot;&amp;Help&quot;);
     helpPopup-&gt;addAction(&quot;&amp;About QtMfc...&quot;, this, SLOT(helpAbout()), Qt::CTRL + Qt::Key_F1);

     view = new ChildView(this);
     setCentralWidget(view);

     statusBar();
 }</pre>
<p>The implementation of the class creates the menu, instantiates the ChildView as the central widget, and adds a status bar.</p>
<pre> void MainFrame::editOptions()
 {
     QDialog *dialog = new QDialog(this);
     dialog-&gt;setAttribute(Qt::WA_DeleteOnClose);
     Ui::OptionsDialog ui;
     ui.setupUi(dialog);

     dialog-&gt;show();
 }

 void MainFrame::helpAbout()
 {
     QMessageBox::about(this, &quot;About QtMfc&quot;, &quot;QtMfc Version 1.0\nCopyright (C) 2003&quot;);
 }</pre>
<p>The slot implementations are identical to the application command handlers in the Qt/MFC hybrid, but of course don't need to use the <a href="qwinwidget.html">QWinWidget</a> class anymore.</p>
<a name="replacing-the-mfc-application"></a>
<h3>Replacing the MFC application</h3>
<p>The final step is to remove the WindowsApp class completely, and handle the application startup and initialization in a multiplatform <tt>main</tt> entry point function.</p>
<pre> TEMPLATE = app
 TARGET   = QtMfc5

 SOURCES += childview.cpp mainframe.cpp qtmfc.cpp
 HEADERS += childview.h   mainframe.h
 FORMS   += ../step4/optionsdialog.ui
 RC_FILE = qtmfc.rc</pre>
<p>We can delete the <tt>qtmfc.h</tt> header file and remove it from the <tt>HEADERS</tt> section in the qmake <tt>.pro</tt> file. We can also remove the linking against the Migration Framework library, and the modifications of the preprocessor symbols.</p>
<p>Then we rerun qmake to regenerate the <tt>.dsp</tt> file. Since we added the <tt>Q_OBJECT</tt> macro to the <tt>MainFrame</tt> class declaration we have to make sure that the meta object compiler, <tt>moc</tt>, is added to the build step for the <tt>MainFrame</tt> class, and this is also done when running qmake.</p>
<p>The <tt>qtmfc.cpp</tt> file is completely replaced.</p>
<pre> #include &lt;QtGui/QApplication&gt;
 #include &quot;mainframe.h&quot;

 int main(int argc, char **argv)
 {
     QApplication app(argc, argv);

     MainFrame frame;
     frame.show();

     return app.exec();
 }</pre>
<p>All it does now is to include the required headers, and to implement a standard main entry point function.</p>
<a name="cleaning-up"></a>
<h3>Cleaning up</h3>
<p>Finally we edit the resource script (with a plain text editor, Visual Studio is too powerful for this) and remove the obsolete entries. The only entry we keep is the application icon.</p>
<pre> IDR_MAINFRAME           ICON    DISCARDABLE     &quot;res\\QtMfc.ico&quot;</pre>
<p>Now we can delete the files that are no longer needed:</p>
<pre> StdAfx.h, StdAfx.cpp, qtmfc.h, res/qtmfc.rc2, resource.h</pre>
<p>The code we have now does the same job as the MFC based code, is much smaller, has less files to maintain and will compile with different compilers for different platforms.</p>
<p /><address><hr /><div align="center">
<table width="100%" cellspacing="0" border="0"><tr class="address">
<td width="30%" align="left">Copyright &copy; 2010 Nokia Corporation and/or its subsidiary(-ies)</td>
<td width="40%" align="center"><a href="http://qt.nokia.com/doc/trademarks.html">Trademarks</a></td>
<td width="30%" align="right"><div align="right">Qt Solutions</div></td>
</tr></table></div></address></body>
</html>
